#include "rain.h"
#include "rainDrop.h"
#include <sstream>
#include "lightning.h"
#include "model/objectModel/fileModel.h"

const unsigned int Rain::lightningCount = 9;
const unsigned int Rain::lightningActivateTickCount = 26;

Rain::Rain(const Cube& cube,float density,Point sceneCenter,Gravity& g,const ObjectModelPtr& dropModel,const ObjectModelPtr& lightningModel)
	: SceneObject(cube,dropModel), gravity(g){
	srand((unsigned)time(0));
	this->density = density;
	this->stopped=false;
	generateDrops();

	this->lightningModel = lightningModel;
	this->tickCount=0;

	createLightning(sceneCenter);

	stop();
}

Rain::~Rain(){
	stop();

	for(std::list<SceneObject*>::iterator it=drops.begin();it!=drops.end();++it)
		delete *it;

	for(unsigned int c=0;c<lightning.size();c++)
		delete lightning[c];
}

void Rain::timeStep(){
	if(stopped)
		return;

	for(unsigned int c=0;c<lightningCount;c++){
		std::ostringstream stream;
		stream << Lightning::name() << c;
		this->findObject(stream.str()).timeStep();
	}
	tickCount++;

	if(tickCount==lightningActivateTickCount){
		activateLightning();
		tickCount=0;
	}
}

void Rain::generateDrops(){
	unsigned int n = (unsigned int)(this->dimensions.width()*this->dimensions.depth()*density);
	unsigned int dropCount = 0;
	for(unsigned int c=0;c<n;c++){
		Point randp;
		randp.x1 = ((float)rand()/(float)RAND_MAX)*(this->dimensions.width()) + this->dimensions.minX();
		randp.x2 = ((float)rand()/(float)RAND_MAX)*(this->dimensions.depth()) + this->dimensions.minY();
		randp.x3 = ((float)rand()/(float)RAND_MAX)*(this->dimensions.center().x3);

		Cube dropCube(Point(0.001f,-0.001f,-0.1f),Point(-0.001f,0.001f,0.01f));
		dropCube.translate(randp.x1,randp.x2,randp.x3);
		RainDrop* drop = new RainDrop(dropCube,this->dimensions,this->objectModel);
		drop->setParent(this);

		std::ostringstream stream;
		stream << RainDrop::name() << dropCount++;
		this->addObject(stream.str(),drop);
		this->drops.push_back(drop);
		gravity.addParticle(drop);
	}
}

void Rain::setModelMatrix(){
	// No debe verse
	//SceneObject::setModelMatrix();
	glScalef(0,0,0);
}

void Rain::setSubModelMatrix(const std::string& name){
}

void Rain::move(float dx,float dy,float dz){
	SceneObject::move(dx,dy,dz);
	for(std::list<SceneObject*>::iterator it=this->drops.begin();it!=this->drops.end();++it){
		static_cast<RainDrop*>(*it)->setRainCube(this->dimensions);
	}
}

void Rain::createLightning(Point sceneCenter){
	// Al principio estan todos desactivados
	Cube lightningCube[lightningCount]= {	Cube(Point(0,-200,0),Point(190,-201,190)),
											Cube(Point(500,-500,0),Point(690,-501,190)),
											Cube(Point(-200,-400,0),Point(-390,-901,190)),
											Cube(Point(300,100,0),Point(210,101,190)),
											Cube(Point(500,600,0),Point(690,601,190)),
											Cube(Point(500,-690,0),Point(690,-691,190)),
											Cube(Point(0,800,0),Point(190,801,190)),
											Cube(Point(500,1000,0),Point(690,1001,190)),
											Cube(Point(-200,900,0),Point(-390,901,190)) };

	float zAngle[lightningCount] = {0,0,0,90,90,90,0,0,0};
	float xAngle[lightningCount] = {0,0,0,0,0,0,0,0,0};

	for(unsigned int c=0;c<lightningCount;c++){
		Lightning* lightning = new Lightning(lightningCube[c],sceneCenter,this->lightningModel);
		lightning->rotate(zAngle[c],xAngle[c]);

		std::ostringstream stream;
		stream << Lightning::name() << c;
		lightning->setStopped(true);
		this->addObject(stream.str(),lightning);
		this->lightning.push_back(lightning);
	}
}

void Rain::activateLightning(){
	// Elijo aleatoramiento cuantos rayos activar
	unsigned int n = (rand()%(lightningCount/2));

	// Elijo aleatoriamente cuales activar
	for(unsigned int c=0;c<n;c++){
		Lightning* lightning = dynamic_cast<Lightning*>(this->lightning[(rand()%lightningCount)]);
		if(lightning->stopped())
			lightning->setStopped(false);
	}
}

void Rain::start(){
	stopped=false;

	unsigned int c;
	for(std::list<SceneObject*>::iterator it=drops.begin();it!=drops.end();++it,c++){
		gravity.addParticle(dynamic_cast<Particle*>(*it));
		std::ostringstream stream;
		stream << RainDrop::name() << c;
		this->addObject(stream.str(),*it);
	}

	for(unsigned int c=0;c<lightningCount;c++){
		std::ostringstream stream;
		stream << Lightning::name() << c;
		this->addObject(stream.str(),lightning[c]);
	}
}

void Rain::stop(){
	if(stopped)
		return;

	for(unsigned int c=0;c<lightningCount;c++){
		std::ostringstream stream;
		stream << Lightning::name() << c;
		dynamic_cast<Lightning&>(this->findObject(stream.str())).setStopped(true);
	}

	for(std::map<std::string,SceneObject*>::iterator it=listObject.begin();it!=listObject.end();++it){
		gravity.removeParticle(dynamic_cast<Particle*>(it->second));
	}
	listObject.clear();

	stopped=true;
}
